﻿using System;
using System.Collections;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using CFG = System.Configuration;
using mshtml;
using SHDocVw;
using System.ComponentModel;
namespace AutomatizzazioneCleverConsumit
{
    public class WebUtil
    {
        #region Fields

        private bool isDocumentComplete = false;
        private InternetExplorer _IE;
        private int _timeoutSeconds = 30;
        private Process m_proc = null;

        #endregion

        #region Properties

        //set the timeout to complete load the document
        public int TimeoutSeconds
        {
            get { return _timeoutSeconds; }
        }

        /// <summary>
        /// instance of IE object
        /// </summary>
        public InternetExplorer IE
        {
            get { return _IE; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// we create a new instance of internet explorer, and get the object asociated with the new iexplore page opened
        /// </summary>
        public WebUtil()
        {
            //start a new IE instance
            ShellWindows m_IEFoundBrowsers = new ShellWindowsClass();
            int deschis = m_IEFoundBrowsers.Count;
            //open a new instance of IExplore, the nomerge attribute is for generate a new HWND for the new instance,
            //other way the new instance will be hooked by the last instance
            m_proc = Process.Start("IExplore.exe", "-nomerge about:blank");
            while (deschis == m_IEFoundBrowsers.Count)
            {
                ///keep program busy till the windows shell get the new instance 
            }
            //get the object of the new IE instance opened
            foreach (InternetExplorer Browser in m_IEFoundBrowsers)
            {
                try
                {
                    if (Browser.HWND == (int)m_proc.MainWindowHandle)
                    {
                        _IE = Browser;
                        break;
                    }
                }
                catch { Logger.Log("unable to open browser",LogType.Error);}
            }
            try
            {
                if (CFG.ConfigurationManager.AppSettings["HideWeb"].ToLower() == "true")
                {
                    IE.Visible = false;
                }
                else
                {
                    IE.Visible = true;
                }
                //attach an event 
                //attach two events
                IE.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(IE_DocumentComplete);
                IE.NavigateError += new DWebBrowserEvents2_NavigateErrorEventHandler(IE_NavigateError);
                //IE.NewWindow3 += new DWebBrowserEvents2_NewWindow3EventHandler(IE_NewWindow3);
            }
            catch (Exception ex) { Logger.Log("IEpage failed to start. Reason: " + ex.Message,LogType.Error); }
        }

        /// <summary>
        /// kill the process asociated to opened IE page
        /// </summary>
        public void ClosePage()
        {
            if (m_proc != null)
            {
                m_proc.Kill();
            }
        }

        /// <summary>
        /// the callback function for navigateError 
        /// if the event raise this function set the PageStatus propertie of the automateProcess
        /// instance with the error code retreived by parameter StatusCode
        /// </summary>
        /// <param name="pDisp"></param>
        /// <param name="URL"></param>
        /// <param name="Frame"></param>
        /// <param name="StatusCode"></param>
        /// <param name="Cancel"></param>
        public void IE_NavigateError(object pDisp, ref object URL, ref object Frame, ref object StatusCode, ref bool Cancel)
        {

        }

        public IHTMLElement getLastElem(string tag)
        {
            HTMLDocument document = ((HTMLDocument)IE.Document);
            IHTMLFramesCollection2 frames = document.frames;
            IHTMLElement el = null;
            object o;
            for (int i = 0; i < frames.length; i++)
            {
                o = i;
                IHTMLWindow2 fr = (IHTMLWindow2)frames.item(ref o);
                HTMLDocument doc = (HTMLDocument)fr.document;
                IHTMLElementCollection colection = doc.getElementsByTagName(tag);
                foreach (IHTMLElement ele in colection)
                {
                    el = ele;
                }
            }
            return el;
        }

        public IHTMLElementCollection getColectionByTag(string tag)
        {
            HTMLDocument document = ((HTMLDocument)IE.Document);
            IHTMLFramesCollection2 frames = document.frames;
            IHTMLElementCollection colection = null;
            object o;
            for (int i = 0; i < frames.length; i++)
            {
                o = i;
                IHTMLWindow2 fr = (IHTMLWindow2)frames.item(ref o);
                HTMLDocument doc = (HTMLDocument)fr.document;
                colection = doc.getElementsByTagName(tag);
            }
            return colection;
        }

        public IHTMLElement GetElementWithText(string text, string tag)
        {
            HTMLDocument document = ((HTMLDocument)IE.Document);
            IHTMLElement el = null;
            IHTMLElementCollection colection = document.getElementsByTagName(tag);
            foreach (IHTMLElement ele in colection)
            {
                if (ele.innerText.ToLower().Contains(text))
                    el = ele;
            }
            if (el == null)
            {
                IHTMLFramesCollection2 frames = document.frames;
                try
                {
                    object o = null;
                    for (int i = 0; i < frames.length; i++)
                    {
                        o = i;
                        IHTMLWindow2 fr = (IHTMLWindow2)frames.item(ref o);
                        HTMLDocument doc = (HTMLDocument)fr.document;
                        IHTMLElementCollection tags = doc.getElementsByTagName(tag);

                        IEnumerator enumerator = tags.GetEnumerator();
                        IHTMLElement finalElement = null;
                        while (enumerator.MoveNext())
                        {
                            IHTMLElement element = (IHTMLElement)enumerator.Current;
                            bool go = false;
                            try
                            {
                                go = element.innerText.ToLower().Contains(text.ToLower());

                            }
                            catch { }
                            if (go)
                            {
                                finalElement = element;
                            }

                            //if (element.innerText == elementValue)
                            //{
                            //    return element;
                            //}
                        }
                        if (finalElement != null)
                        {
                            return finalElement;
                        }
                    }

                }
                catch (Exception ex)
                {
                    string x = ex.Message;
                }
            }



            return el;
        }


        #region click anchor tag
        public void ClickAnchor(string anchorId)
        {
            isDocumentComplete = false;
            HTMLAnchorElement input = GetAnchorElement(anchorId);
            input.click();
            WaitForComplete();
        }

        public void ClickAnchorWithParent(string parentControlId, string anchorId)
        {

            isDocumentComplete = false;
            anchorId = parentControlId + anchorId;
            HTMLAnchorElement input = GetAnchorElement(anchorId);
            input.click();
            WaitForComplete();
        }

        //public void ClickAnchorWithValue(string anchorValue)
        //{
        //    HTMLAnchorElement anchor = (HTMLAnchorElement)GetElementByValue("A", anchorValue);
        //    anchor.click();
        //    WaitForComplete();
        //}


        #endregion

        /// <summary>
        /// click on the specific button,
        /// modified to click on a table cell
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="attribut"></param>
        /// <param name="attValue"></param>
        public string ClickButton(string tag, string attribut, string attValue)
        {
            string output = "OK";
            try
            {
                isDocumentComplete = false;

                //this is a particular typw, when the element don't have a distinct attribute or the attribute is generated dinamicaly, then serch the element by text
                if (attribut == "inner text")
                {
                    HTMLAnchorElement el = ((HTMLAnchorElement)GetElementWithText(attValue, tag));
                    el.click();
                    WaitForComplete();
                    output = "OK";
                    return output;
                }
                else
                {

                    if (tag == "td")
                    {
                        HTMLTableCell input1 = (HTMLTableCell)GetElementById(attValue);
                        input1.click();
                        WaitForComplete();
                    }
                    else
                    {
                        if (tag == "div")
                        {
                            HTMLDivElement input = (HTMLDivElement)GetElementByValue(tag, attribut, attValue);
                            if (attValue != "MenuConversazioni_ListMenuConversazioni2_1")
                            {
                                HTMLDivElement in2 = (HTMLDivElement)input.firstChild;
                                in2.click();
                                WaitForComplete();
                            }
                            else
                            {
                                input.click();
                                WaitForComplete();
                            }
                        }
                        else
                        {

                            if (tag.ToLower() == "a")
                            {
                                HTMLAnchorElement input = (HTMLAnchorElement)GetElementByValue(tag, attribut, attValue);
                                input.click();
                                WaitForComplete();
                            }
                            else
                            {
                                HTMLInputElementClass input = (HTMLInputElementClass)GetElementByValue(tag, attribut, attValue);
                                input.click();
                                WaitForComplete();
                            }
                        }
                    }
                }
            }
            catch
            {
                output = "ERR";
            }
            return output;

        }

        /// <summary>
        /// click on a check box
        /// </summary>
        /// <param name="anchorId"></param>
        public void ClickCheckbox(string anchorId)
        {
            isDocumentComplete = false;
            HTMLInputElement input = GetCheckboxElement(anchorId);

            input.click();
        }

        /// <summary>
        /// verify if a element exist
        /// </summary>
        /// <param name="elementId"></param>
        /// <returns></returns>
        public bool DoesElementExist(string elementId)
        {
            IHTMLElement input = GetElementById(elementId);
            return input != null;
        }

        /// <summary>
        /// return the Attribute value of an element with specified id
        /// </summary>
        /// <param name="elementId">element id</param>
        /// <param name="attributeName">attribute name</param>
        /// <returns></returns>
        public object GetElementAttribute(string elementId, string attributeName)
        {
            IHTMLElement element = GetElementById(elementId);
            if (element == null)
            {
                return null;
            }
            return element.getAttribute(attributeName, 0);
        }

        public object GetElementAtribute(IHTMLElement elem, string attributeName)
        {
            return elem.getAttribute(attributeName, 0);
        }


        /// <summary>
        /// return a element with the specific id
        /// </summary>
        /// <param name="elementId"></param>
        /// <returns></returns>
        public IHTMLElement GetElementById(string elementId)
        {
            HTMLDocument document = ((HTMLDocument)IE.Document);
            IHTMLElement element = document.getElementById(elementId);
            int nullElementCount = 0;
            // The following loop is to account for any latency that IE
            // might experience.  Tweak the number of times to attempt
            // to continue checking the document before giving up.
            while (element == null && nullElementCount < 10)
            {
                Thread.Sleep(500);
                element = document.getElementById(elementId);
                nullElementCount++;
            }

            return element;
        }

        public string GetInputValue(string inputId)
        {
            HTMLInputElementClass input = GetInputElement(inputId);

            if (input == null)
            {
                return null;
            }

            return input.value;
        }

        //navigate to a gived url
        public void Navigate(string url)
        {
            isDocumentComplete = false;
            object empty = "";
            IE.Navigate(url, ref empty, ref empty, ref empty, ref empty);
            WaitForComplete();
        }

        //navigate to a gived url
        public bool Navigate(string url, int i)
        {
            isDocumentComplete = false;
            object empty = "";
            IE.Navigate(url, ref empty, ref empty, ref empty, ref empty);
            WaitForComplete();
            if (isDocumentComplete)
                return true;
            return false;
        }

        public void SetCheckboxValue(string checkboxId, bool isChecked, bool failIfNotExist)
        {
            HTMLInputElementClass input = GetInputElement(checkboxId);

            if (input == null && failIfNotExist)
            {
                throw new ApplicationException("CheckBox ID: " + checkboxId + " was not found.");
            }
            if (input != null)
            {
                input.@checked = isChecked;
            }
        }

        /// <summary>
        /// complete a text box with a gived value
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="attribute"></param>
        /// <param name="attValue"></param>
        /// <param name="value"></param>
        public string SetInputStringValue(string tag, string attribute, string attValue, string value)
        {
            string output = "OK";
            try
            {
                HTMLInputElementClass input = (HTMLInputElementClass)GetElementByValue(tag, attribute, attValue);
                input.value = value;
            }
            catch (Exception ex)
            {
                output = ex.Message;    
            }
            return output;
        }

        /// <summary>
        /// set the input value for an HTMLInputElement
        /// </summary>
        /// <param name="inputId"></param>
        /// <param name="elementValue"></param>
        public void SetInputIntValue(string inputId, int elementValue)
        {
            HTMLInputElementClass input = GetInputElement(inputId);
            input.value = elementValue.ToString();
        }

        public void SelectValueByIndex(string inputId, int index)
        {
            HTMLSelectElementClass input = (HTMLSelectElementClass)GetSelectElement(inputId);
            input.selectedIndex = index;
        }

        /// <summary>
        /// return the specific IHTMLElement gived by tag and a specific attribute value
        /// i am in deep shit if the user change the id value of a control
        /// </summary>
        /// <param name="tagName"></param>
        /// <param name="attName"></param>
        /// <param name="attValue"></param>
        /// <returns></returns>
        public IHTMLElement GetElementByValue(string tagName, string attName, string attValue)
        {
            int nullElementCount = 0;



            IHTMLElement element = GetElementByValueOnce(tagName, attName, attValue);
            while (element == null && nullElementCount < 10)
            {
                Thread.Sleep(500);
                element = GetElementByValueOnce(tagName, attName, attValue);
                nullElementCount++;
            }

            return element;
        }

        /// <summary>
        /// get an HTMLanchorElement who have the gived id
        /// </summary>
        /// <param name="inputId"></param>
        /// <returns></returns>
        private HTMLAnchorElement GetAnchorElement(string inputId)
        {
            return (HTMLAnchorElement)GetElementById(inputId);
        }

        /// <summary>
        /// get an HTMLInputElement of type checkbox
        /// </summary>
        /// <param name="inputId"></param>
        /// <returns></returns>
        private HTMLInputElement GetCheckboxElement(string inputId)
        {
            return (HTMLInputElement)GetElementById(inputId);
        }

        /// <summary>
        /// get the first element who have the gived tag , attribute and value 
        /// </summary>
        /// <param name="tagName"></param>
        /// <param name="attName"></param>
        /// <param name="attValue"></param>
        /// <returns></returns>
        private IHTMLElement GetElementByValueOnce(string tagName, string attName, string attValue)
        {
           
            HTMLDocument document = ((HTMLDocument)IE.Document);
            IHTMLElement el = null;

            IHTMLElementCollection tags = document.getElementsByTagName(tagName);

            IEnumerator enumerator = tags.GetEnumerator();

            while (enumerator.MoveNext())
            {
                IHTMLElement element = (IHTMLElement)enumerator.Current;
                if (element.getAttribute(attName, 0).ToString().Contains(attValue))
                {
                    return element;
                }
            }
            if (el == null)
            {
                
                IHTMLFramesCollection2 frames = (IHTMLFramesCollection2)document.frames;
                try
                {
                    object o = null;
                    for (int i = 0; i < frames.length; i++)
                    {
                        o = i;
                        IHTMLWindow2 fr = (IHTMLWindow2)frames.item(ref o);
                        HTMLDocument doc = (HTMLDocument)fr.document;
                        tags = doc.getElementsByTagName(tagName);

                        enumerator = tags.GetEnumerator();

                        while (enumerator.MoveNext())
                        {
                            IHTMLElement element = (IHTMLElement)enumerator.Current;
                            bool go = false;
                            try
                            {
                                go = element.getAttribute(attName, 0).ToString().Contains(attValue);

                            }
                            catch { }
                            if (go)
                            {
                                return element;
                            }

                            //if (element.innerText == elementValue)
                            //{
                            //    return element;
                            //}
                        }
                    }

                }
                catch (Exception ex)
                {
                    string x = ex.Message;
                }
            }




            return null;
        }

        /// <summary>
        /// return an HTMLInputElement
        /// </summary>
        /// <param name="inputId"></param>
        /// <returns></returns>
        private HTMLInputElementClass GetInputElement(string inputId)
        {
            return (HTMLInputElementClass)GetElementById(inputId);
        }

        /// <summary>
        /// Return the selected element
        /// </summary>
        /// <param name="inputId"></param>
        /// <returns></returns>
        private HTMLSelectElement GetSelectElement(string inputId)
        {
            return (HTMLSelectElement)GetElementById(inputId);
        }

        //wait for a page to load completly
        public void WaitForComplete()
        {
            int elapsedSeconds = 0;
            while (!isDocumentComplete && elapsedSeconds != TimeoutSeconds)
            {
                Thread.Sleep(1000);
                elapsedSeconds++;
            }
        }

        /// <summary>
        /// callback for event DocumentComplete
        /// </summary>
        /// <param name="pDisp"></param>
        /// <param name="URL"></param>
        private void IE_DocumentComplete(object pDisp, ref object URL)
        {
            isDocumentComplete = true;
        }

        private void IE_NewWindow3(object sender, CancelEventArgs e)
        {
            MessageBox.Show("O PAGINA NOUA DESCHISA");
            IHTMLElementCollection cont =  (IHTMLElementCollection)IE.Container;
            foreach (IHTMLElement contelem in cont)
            {
                
            }

        }

        public string GetInnerHTML()
        {
            //AutoResetEvent firstDocumentCompleted = new AutoResetEvent(false);
            //firstDocumentCompleted.WaitOne(1000);
            HTMLDocument document = (HTMLDocument)IE.Document;
            IHTMLElement el = null;
            string deIntors = string.Empty;

            if (el == null)
            {
                try
                {

                    IHTMLFramesCollection2 frames = (IHTMLFramesCollection2)document.frames;
                    try
                    {
                        object o = null;
                        for (int i = 0; i < frames.length; i++)
                        {
                            o = i;
                            IHTMLWindow2 fr = (IHTMLWindow2)frames.item(ref o);
                            HTMLDocument doc = (HTMLDocument)fr.document;
                            deIntors += doc.body.innerHTML;
                        }

                    }
                    catch (Exception ex)
                    {
                        string x = ex.Message;
                    }
                }
                catch (InvalidCastException ex)
                {
                    string s = ex.Message;
                    deIntors += document.body.innerHTML;
                }
            }
            try
            {
                if (string.IsNullOrEmpty(deIntors.Trim()))
                {
                    deIntors += document.body.innerHTML;
                }
            }
            catch { }
            return deIntors;
        }

        public string GetTableInnerText()
        {
            HTMLDocument doce = ((HTMLDocument)IE.Document);
            IHTMLFramesCollection2 frames = doce.frames;
            try
            {
                object o = null;
                for (int i = 0; i < frames.length; i++)
                {
                    o = i;
                    IHTMLWindow2 fr = (IHTMLWindow2)frames.item(ref o);
                    HTMLDocument doc = (HTMLDocument)fr.document;
                    IHTMLElementCollection tables = doc.getElementsByTagName("table");
                    IEnumerator tablesEnum = tables.GetEnumerator();
                    while (tablesEnum.MoveNext())
                    {
                        IHTMLElement element = (IHTMLElement)tablesEnum.Current;
                        if (element.innerText.Contains("INSOLUTO/SCONF"))
                            return element.innerText;
                    }
                }

            }
            catch (Exception ex)
            {
                string x = ex.Message;
            }
            return string.Empty;
        }

        #endregion
    }
}

